package com.codegravity.mobile.expensms;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.view.Display;
import android.view.WindowManager;
import android.widget.RemoteViews;

public class SMSExpenseAppWidgetProvider extends AppWidgetProvider {
	int adjustWK = 0;
	Calendar calendar = Calendar.getInstance();
	static boolean isSun;
	int scrn_wth, scrn_ht;
	List<Float> expense_lst;
	List<Integer> expense_cnt;
	String weeks;
	long end_time = 0, start_time = 0;
	Date end_date = null, start_date = null;
	DateFormat formatter = new SimpleDateFormat("dd/MM/yyyy");
	float mnth_expense = 0;
	float week_expense = 0;

	public void onUpdate(Context context, AppWidgetManager appWidgetManager,
			int[] appWidgetIds) {
		final int N = appWidgetIds.length;
		init(context);
		RemoteViews views;
		views = new RemoteViews(context.getPackageName(),
				R.layout.widget_layout);
		Intent intent = new Intent(context,
				com.codegravity.mobile.expensms.ChartsGallery.class);
		PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,
				intent, 0);

		for (int k = 0; k < N; k++) {
			int appWidgetId = appWidgetIds[k];
			views.setOnClickPendingIntent(R.id.widget_lay, pendingIntent);

			initCalendar();
			initList();
			findWeek();

			calendar.add(Calendar.DAY_OF_MONTH, -1);
			start_time = calendar.getTimeInMillis();

			ExpenseDataBase db = new ExpenseDataBase(context);
			db.open();
			Cursor cursor = db.fetchAllAlert(ExpenseDataBase.EXPENSE_TABLE,
					ExpenseDataBase.EXPENSE_INT, start_time, end_time);

			if (cursor == null)
				continue;

			try {
				if (cursor.getCount() > 0) {
					cursor.moveToFirst();
					Date current_date = fetchData(cursor);
					calMonthlyAvg(current_date, db);
				}
				cursor.close();
				db.close();
				drawChart(views, context);
				SharedPreferences myPrefs = context.getSharedPreferences(
						"SMSExpense", Context.MODE_WORLD_READABLE);

				SharedPreferences.Editor prefsEditor = myPrefs.edit();
				prefsEditor.putInt(AppWidgetManager.EXTRA_APPWIDGET_ID,
						appWidgetId);
				prefsEditor.commit();
				appWidgetManager.updateAppWidget(appWidgetId, views);
			} catch (Exception e) {
				System.out.println("error " + e.getMessage());
				e.printStackTrace();
			}
		}
	}

	private void init(Context context) {
		Display display = ((WindowManager) context
				.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
		scrn_wth = display.getWidth();
		scrn_ht = display.getHeight();
		SharedPreferences myPrefs = context.getSharedPreferences("SMSExpense",
				Context.MODE_WORLD_READABLE);
		isSun = myPrefs.getBoolean("weekSun", false);
		if (isSun)
			adjustWK = 0;
		else
			adjustWK = 1;
	}

	private void drawChart(RemoteViews views, Context context) {
		ExpenseBarChart chart;
		chart = new ExpenseBarChart(context, expense_lst, expense_cnt, weeks,
				week_expense, mnth_expense, 1, isSun ? 0 : 1);

		chart.setDrawingCacheEnabled(true);
		int widget_width = (int) (scrn_wth - (scrn_wth * 0.05));
		int widget_height = (int) (scrn_ht - (scrn_ht * 0.20));
		chart.measure(widget_width, widget_height);
		chart.layout(0, 0, (int) widget_width, widget_height);
		chart.invalidate();
		Bitmap bitmap = chart.getDrawingCache();
		views.setImageViewBitmap(R.id.chart, bitmap);
	}

	private void calMonthlyAvg(Date current_date, ExpenseDataBase db) {
		calendar.setTime(end_date);
		calendar.set(Calendar.DAY_OF_MONTH, 1);
		calendar.add(Calendar.DAY_OF_MONTH, -1);
		long monthStart = calendar.getTimeInMillis();
		calendar.setTime(current_date);
		long monthCurr = calendar.getTimeInMillis();

		Cursor cur_avg = db.fetchAllAlert(ExpenseDataBase.EXPENSE_TABLE,
				ExpenseDataBase.EXPENSE_INT, monthStart, monthCurr);
		if (cur_avg.getCount() > 0) {
			cur_avg.moveToFirst();
			do {
				mnth_expense = mnth_expense + cur_avg.getFloat(1);
			} while (cur_avg.moveToNext());
		}
		cur_avg.close();

		mnth_expense = mnth_expense / calendar.get(Calendar.DAY_OF_MONTH);
	}

	private Date fetchData(Cursor cursor) {
		Date current_date;
		do {
			current_date = new Date(cursor.getLong(2));
			calendar.setTime(current_date);
			if (current_date.compareTo(end_date) <= 0) {
				int day = getCalDAY(Calendar.DAY_OF_WEEK);
				expense_lst.set(day - 1,
						expense_lst.get(day - 1) + cursor.getFloat(1));
				expense_cnt.set(day - 1, expense_cnt.get(day - 1) + 1);
				week_expense = week_expense + cursor.getFloat(1);
			}
		} while (cursor.moveToNext());
		week_expense = week_expense / getCalDAY(Calendar.DAY_OF_WEEK);
		return current_date;
	}

	private void findWeek() {
		calendar.add(Calendar.DAY_OF_MONTH, 7 - getCalDAY(Calendar.DAY_OF_WEEK));
		end_date = calendar.getTime();
		end_time = calendar.getTimeInMillis();
		calendar.add(Calendar.DAY_OF_MONTH, -6);

		start_date = calendar.getTime();
		start_time = calendar.getTimeInMillis();

		weeks = formatter.format(start_date) + " to "
				+ formatter.format(end_date);
	}

	private void initList() {
		expense_lst = new ArrayList<Float>();
		expense_cnt = new ArrayList<Integer>();
		for (int i = 0; i < 7; i++) {
			expense_lst.add((float) 0);
			expense_cnt.add(0);
		}
	}

	private void initCalendar() {
		calendar.set(Calendar.HOUR, calendar.getActualMaximum(Calendar.HOUR));
		calendar.set(Calendar.MINUTE,
				calendar.getActualMaximum(Calendar.MINUTE));
		calendar.set(Calendar.SECOND,
				calendar.getActualMaximum(Calendar.SECOND));
		calendar.set(Calendar.AM_PM, Calendar.PM);
	}

	int getCalDAY(int field) {
		if ((calendar.get(field) - adjustWK) != 0)
			return calendar.get(field) - adjustWK;
		else
			return 7;
	}
}
